#include "vtor_shell.h"
#include "vtor_string.h"
#include "vtor_timer.h"

#ifdef __VTOR_SHELL__

VtorShell* VtorShell_shellHeader = NULL;

void VtorShell_Void(void)
{
}

int32_t VtorShell_Icon(void)
{
	// https://www.lddgo.net/string/text-to-ascii-art
	// Slant Fitted 
	VtorShell_PrintString("\r\n");
	
	VtorShell_PrintString("          __                         __           __ __\r\n");
	VtorShell_PrintString("  _   __ / /_ ____   _____    _____ / /_   ___   / // /\r\n");
	VtorShell_PrintString(" | | / // __// __ \\ / ___/   / ___// __ \\ / _ \\ / // / \r\n");
	VtorShell_PrintString(" | |/ // /_ / /_/ // /      (__  )/ / / //  __// // /  \r\n");
	VtorShell_PrintString(" |___/ \\__/ \\____//_/      /____//_/ /_/ \\___//_//_/   \r\n");
	
	VtorShell_PrintString("\r\n");
	VtorShell_PrintString("\r\n");
	return 0;
}


void VtorShell_Help(void)
{
	VtorShell_PrintString("\tVtorShell_Help(void)\r\n");
	VtorShell_PrintString("\tVtorShell designed by vtor3478@qq.com\r\n");
	VtorShell_PrintString("\tcurrent date 2024-10-18\r\n\r\n");
	
	VtorShell_PrintString("\texample:\r\n");
	VtorShell_PrintString("\t\tlist\r\n");
	VtorShell_PrintString("\t\tvoid\r\n");
	VtorShell_PrintString("\t\tint 20 \r\n");
	VtorShell_PrintString("\t\tint 0x24 \r\n");
	VtorShell_PrintString("\t\tstr \"123abc\" \r\n");
	VtorShell_PrintString("\t\thexstr '12 3a bc ef'\r\n");
	VtorShell_PrintString("\t\tmem :123abc \r\n");

	/*
	注意，新增了 str hexstr mem参数，
	str 使用 英文双引号 " 包起来，自带长度信息，
		遇到null会结束，无法嵌套 英文双引号
		举例 "123ab" ，实际上是0x31 0x32 0x33 0x41 0x42
		
	hexstr 使用 英文单引号 包起来，缺少长度信息
		建议在前面新增一个整型变量表示长度信息
		hexstr实际上是使用十六进制表示字符，
			可便于modbus rtu等十六进制设备的调试
		遇到null或:或其他异常字符会结束，
			内部数据只能是    0~9，a-f，A-F，空格
		举例 '123abc' ，实际上是0x12 0x3a 0xbc
		如果内部长度为奇数，会忽略掉最后一个数据，
			为保证数据稳定性，最好使用偶数个数据
		
		
	mem 使用 英文冒号作为开始符号，缺少长度，
		建议在前面新增一个整型变量表示长度信息
		mem参数没有结束符，所以仅能作为最后一个参数
		mem参数没有结束符，所以可以支持0x00等特殊数值
		举例 :12ab，实际上是0x31 0x32 0x41 0x42 ...(后续不确定)
		
	*/
}

int32_t VtorShell_List(void)
{
	VtorShell* shell = VtorShell_shellHeader;
	int32_t shellCnt = 0;
	if(NULL == shell)
	{
		return 0;
	}
	while(NULL != shell->shellFun)
	{
		uint8_t shellListBuf[50] = {0};
		uint8_t* str = shellListBuf;
		int32_t len = 50;
		VtorString_Clear(str);
		str = VtorString_AppendString(str, &len, "\t");
		str = VtorString_AppendString(str, &len, shell->shellName);
		str = VtorString_AppendString(str, &len, "\r\n");
		VtorShell_PrintString(shellListBuf);
		shell++;
		shellCnt++;
	}
	return shellCnt;
}

int32_t VtorShell_Int(int32_t num)
{
	uint8_t buf[50] = { 0 };
	uint8_t* str = buf;
	int32_t len = 50;
	VtorString_Clear(str);
	str = VtorString_AppendString(str, &len, "\tVtorShell_Int(");
	str = VtorString_AppendInt(str, &len, num);
	str = VtorString_AppendString(str, &len, ") = hex(0x");
	str = VtorString_AppendHex(str, &len, num);
	str = VtorString_AppendString(str, &len, ")\r\n");
	VtorShell_PrintString(buf);
	return num;
}

int32_t VtorShell_String(uint8_t* str)
{
	uint8_t buf[100] = { 0 };
	uint8_t* infoStr = buf;
	int32_t len = 100;
	VtorString_Clear(buf);
	infoStr = VtorString_AppendString(infoStr, &len, "\tVtorShell_String(\"");
	infoStr = VtorString_AppendString(infoStr, &len, str);
	infoStr = VtorString_AppendString(infoStr, &len, "\")\r\n");
	VtorShell_PrintString(buf);
	return 0;
}

int32_t VtorShell_HexString(uint8_t* hexstr)
{
	uint8_t buf[100] = { 0 };
	uint8_t* infoStr = buf;
	int32_t strlen = 100;
	VtorString_Clear(buf);
	infoStr = VtorString_AppendString(infoStr, &strlen, "\tVtorShell_HexString('");
	infoStr = VtorString_AppendMemory(infoStr, &strlen, hexstr, 10, 1);
	infoStr = VtorString_AppendString(infoStr, &strlen, "')\r\n");
	return VtorShell_PrintString(buf);
}

int32_t VtorShell_Memory(uint8_t* memBuf)
{
	uint8_t buf[150] = { 0 };
	int32_t strlen = 150;
	uint8_t* str = buf;
	VtorString_Clear(str);
	str = VtorString_AppendString(str, &strlen, "VtorShell_Memory :");
	str = VtorString_AppendMemory(str, &strlen, memBuf, 10, 1);
	str = VtorString_AppendString(str, &strlen, "\r\n");
	return VtorShell_PrintString(buf);
}

int32_t VtorShell_Call(uint32_t addr)
{
	return addr;
}

int32_t VtorShell_WriteInt32(int32_t addr, int32_t val)
{
	*(int32_t*)addr = val;
	return *(int32_t*)addr;
}

int32_t VtorShell_ReadInt32(int32_t addr)
{
	return *(int32_t*)addr;
}

int32_t VtorShell_WriteMem(uint32_t addr, uint8_t* buf, int32_t cnt, int8_t width)
{
	int8_t* byteMem = (int8_t*)addr;
#ifdef __VTOR_STRING_CONFIG_LITTLE_ENDIAN__
	byteMem += width;
#endif
	while(cnt--)
	{
		int i;
		for(i = 0; i < width; i++)
		{
#ifdef __VTOR_STRING_CONFIG_LITTLE_ENDIAN__
			*--byteMem = *buf++;
#else
			*byteMem++ = *buf++;
#endif
		}
#ifdef __VTOR_STRING_CONFIG_LITTLE_ENDIAN__
		byteMem += (width << 1);
#endif
	}
	return *(int32_t*)addr;
}

int32_t VtorShell_ReadMem(uint32_t addr, int32_t cnt, int8_t width)
{
	uint8_t buf[150] = { 0 };
	int32_t strlen = 150;
	uint8_t* str = buf;
	VtorString_Clear(str);
	str = VtorString_AppendString(str, &strlen, "readmem :");
	str = VtorString_AppendMemory(str, &strlen, (uint32_t*)addr, cnt, width);
	str = VtorString_AppendString(str, &strlen, "\r\n");
	VtorShell_PrintString(buf);
	return *(int32_t*)addr;
}

#ifndef __VTOR_SHELL_CONFIG_GET_TIME_BY_USERSELF__
int32_t VtorShell_GetTime()
{
#ifdef __VTOR_TIMER__
	return VtorTimer_GetTick();
#else
	return 0;
#endif
}
#endif // __VTOR_SHELL_CONFIG_GET_TIME_BY_USERSELF__


VtorShell* VtorShell_GetShell(uint8_t* str)
{
	int16_t mostSimilarity = 0;
	VtorShell* shell = VtorShell_shellHeader;
	VtorShell* mostSimilarityShell = NULL;
	if(NULL == shell)
	{
		return NULL;
	}
	while(shell->shellFun)
	{
		int16_t similarity = VtorString_GetSimilarity(str, shell->shellName);
		if(similarity > 50 // 有足够的相似度
			&& similarity > mostSimilarity) // 并且比历史最高更高
		{
			// 记录最大相似度的shell
			mostSimilarityShell = shell;
			mostSimilarity = similarity;
		}
		shell++;
	}
	// 返回相似度最高的shell
	return mostSimilarityShell;
}

int32_t VtorShell_GetArg(uint8_t* str, int32_t* argv, int8_t* argt)
{
	//char* splitArray = {" (),"};
	int8_t argc = 0;

	// 允许括号和空格作为分隔符，而且使用使用较小的那个分隔符
	uint8_t* spaceStr = VtorString_FindString(str, " ");
	uint8_t* bracketStr = VtorString_FindString(str, "(");
	uint8_t* argStr = spaceStr < bracketStr ? spaceStr  : bracketStr;
	uint8_t finishFlag = 0;
	while(*argStr && 0 == finishFlag)
	{
		argStr = VtorString_GetNextValueType(argStr, argt);
		if(VtorVar_Void == *argt)
		{
			break;
		}
		
		if(VtorVar_Int == *argt || VtorVar_Hex == *argt)
		{
			argStr = VtorString_FindInt(argStr, argv);
		}
		else if(VtorVar_String == *argt)
		{
			argStr = VtorString_CutString(argStr, argv);
		}
		else if(VtorVar_HexString == *argt)
		{
			argStr = VtorString_CutHexString(argStr, argv);
		}
		else if(VtorVar_Memory == *argt)
		{
			*argv = (uint32_t)(argStr + 1); // 后续都是mem
			finishFlag = 1;
		}
		argv++;
		argc++;
		argt++;
	}
	return argc;
}

void VtorShell_PrintArg(VtorShell* shell, uint8_t argc, int32_t* argv, int8_t* argt)
{
	uint8_t i = 0;
	uint8_t infoBuf[127] = {0};
	int32_t len = 127;
	uint8_t* infoStr = infoBuf;
	// 模仿python，3个右尖括号表示输入
	infoStr = VtorString_AppendString(infoStr, &len, "\r\n>>> ");
	infoStr = VtorString_AppendString(infoStr, &len, shell->shellName);
	infoStr = VtorString_AppendString(infoStr, &len, " ");
	for(i = 0; i < argc; i++)
	{
		if(VtorVar_Int == argt[i])
		{
			infoStr = VtorString_AppendInt(infoStr, &len, argv[i]);
		}
		else if(VtorVar_Hex == argt[i])
		{
			infoStr = VtorString_AppendString(infoStr, &len, "0x");
			infoStr = VtorString_AppendHex(infoStr, &len, argv[i]);
		}
		else if(VtorVar_String == argt[i])
		{
			infoStr = VtorString_AppendString(infoStr, &len, "\"");
			infoStr = VtorString_AppendString(infoStr, &len, (uint8_t*)(argv[i]));
			infoStr = VtorString_AppendString(infoStr, &len, "\"");
		}
		else if(VtorVar_HexString == argt[i])
		{
			infoStr = VtorString_AppendString(infoStr, &len, " '");
			infoStr = VtorString_AppendMemory(infoStr, &len, (void*)argv[i], 10, 1);
			infoStr = VtorString_AppendString(infoStr, &len, "'");
		}
		else if(VtorVar_Memory == argt[i])
		{
			infoStr = VtorString_AppendString(infoStr, &len, ":");
			infoStr = VtorString_AppendMemory(infoStr, &len, (void*)argv[i], 10, 1);
		}
		if(i == argc - 1)
		{
			break;
		}
		infoStr = VtorString_AppendString(infoStr, &len, " ");
	}
	infoStr = VtorString_AppendString(infoStr, &len, "\r\n");
	VtorShell_PrintString(infoBuf);
}

void VtorShell_PrintRet(int32_t retVal, int32_t execTick)
{
	uint8_t retBuf[127] = {0};
	int32_t len = 127;
	uint8_t* retStr = retBuf;
	// 模仿python，3个左尖括号表示shell结束，将输出汇总到一行，节省空间
	retStr = VtorString_AppendString(retStr, &len, "<<< return ");
	retStr = VtorString_AppendInt(retStr, &len, retVal);
	retStr = VtorString_AppendString(retStr, &len, " (0x");
	retStr = VtorString_AppendHex(retStr, &len, retVal);
	retStr = VtorString_AppendString(retStr, &len, "); // elapsed ");
	retStr = VtorString_AppendInt(retStr, &len, execTick);
	retStr = VtorString_AppendString(retStr, &len, " tick\r\n");
	VtorShell_PrintString(retBuf);
}

void VtorShell_PrintNumber(int32_t num, int8_t len)
{
	VtorString_PrintNumber(num, len);
}

#ifdef __VTOR_SHELL_CONFIG_MINI__

int32_t VtorShell_Scan(uint8_t* str)
{
	int32_t shellRet = 0;
	VtorShell* shell = VtorShell_shellHeader;
	while(shell->shellFun)
	{
		if(0 == strncmp(shell->shellName, str, strlen(shell->shellName)))
		{
			VtorShell_PrintString(">>> ");
			VtorShell_PrintString(shell->shellName);
			VtorShell_PrintString("\r\n");
			shellRet = shell->shellFun();
			VtorShell_PrintString("<<< ");
			VtorShell_PrintNumber(shellRet, 5);
			VtorShell_PrintString("\r\n");
			break;
		}
		shell++;
	}
	return shellRet;
}

#else // __VTOR_SHELL_CONFIG_MINI__

int32_t VtorShell_Scan(uint8_t* userStr)
{
	uint8_t str[256] = {0};
	uint8_t* shellStr = NULL;
	VtorShell* shell = NULL;
	memcpy(str, userStr, 255); // 保留最后一个字符作为结束符
	// 允许前有空格或者tab，允许后面有 双上坡斜杠作注释
	shellStr = VtorString_Preprocess(str);
	shell = VtorShell_GetShell(shellStr);
	if(shell)
	{
		int32_t argValueBuf[10] = { 0 }; // 使用int32_t存储数值
		int8_t argTypeBuf[10] = { 0 }; // 使用int32_t存储另外类型
		
		// 提取函数名，参数个数，，参数类型
		VtorShellFun shellFun = shell->shellFun;
		int32_t* argv = argValueBuf;
		int8_t* argt = argTypeBuf;
		uint32_t execTick = 0;
		int32_t retVal = 0;

		int8_t argc = VtorShell_GetArg(shellStr, argv, argt);
		VtorShell_PrintArg(shell, argc, argv, argt);
		
		if(VtorString_GetSimilarity(shell->shellName, "call") > 50) // 如果是函数地址调用
		{
			// 如果是函数调用，那么移动参数指针，调整参数个数
			shellFun = (VtorShellFun)argv[0];
			argc--;
			argv++;
		}
		execTick = VtorShell_GetTime();

		retVal = VtorShell_Exec(shellFun, argc, argv);

		execTick = VtorShell_GetTime() - execTick;
		VtorShell_PrintRet(retVal, execTick);
		return retVal;
	}
	return 0;
}

#endif // __VTOR_SHELL_CONFIG_MINI__

int32_t VtorShell_Exec(VtorShellFun shellFun, uint8_t argc, int32_t* argv)
{
	int32_t ret = 0;
	switch (argc)
	{
	case 0:
		ret = ((VtorShellFun0)shellFun)();
		break;
	case 1:
		ret = ((VtorShellFun1)shellFun)(argv[0]);
		break;
	case 2:
		ret = ((VtorShellFun2)shellFun)(argv[0], argv[1]);
		break;
	case 3:
		ret = ((VtorShellFun3)shellFun)(argv[0], argv[1], argv[2]);
		break;
#ifdef __VTOR_SHELL_CONFIG_PARAMS_4__
	case 4:
		ret = ((VtorShellFun4)shellFun)(argv[0], argv[1], argv[2], argv[3]);
		break;
	case 5:
		ret = ((VtorShellFun5)shellFun)(argv[0], argv[1], argv[2], argv[3], argv[4]);
		break;
	case 6:
		ret = ((VtorShellFun6)shellFun)(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
		break;
	case 7:
		ret = ((VtorShellFun7)shellFun)(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
		break;
	case 8:
		ret = ((VtorShellFun8)shellFun)(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
		break;
	case 9:
		ret = ((VtorShellFun9)shellFun)(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
		break;
	case 10:
		ret = ((VtorShellFun10)shellFun)(argv[0], argv[1], argv[2], argv[2], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
		break;
#endif
	default:
		break;
	}
	return ret;
}







#endif // __VTOR_SHELL__

